require_relative "../Expr"

# Expression for unary operators
#
# @author Paul T.
class Calcula::Exprs::UnaryExpr < Calcula::Expr

  # @param op [Calcula::Token] Should have type prefixed with `OP_`
  # @param base [Calcula::Expr]
  # @param prefixed [true, false]
  def initialize(op, base, prefixed:)
    @op = op
    @base = base
    @prefixed = prefixed
  end

  # @see Calcula::Expr#to_s
  # @param (see Calcula::Expr#to_s)
  # @return (see Calcula::Expr#to_s)
  def to_s(form: :src)
    baseTxt = @base.to_s(form: form)
    case form
    when :src then
      @prefixed ? "#{@op.text}#{baseTxt}" : "#{baseTxt}#{@op.text}"
    when :tree then
      "(#{@op.text} #{baseTxt})"
    when :ruby then
      if @prefixed then
        case @op.id
        when :OP_ADD then
          "(#{baseTxt}).abs"
        when :NOT then
          "!(#{baseTxt})"
        else
          "#{@op.text}#{baseTxt}"
        end
      else
        case @op.id
        when :ROUND_DOLLAR then
          "(#{baseTxt}).to_f.round(2)"
        when :DISP then
          "puts _ = #{baseTxt}\n_"
        when :ASSERT then
          "_ = #{baseTxt}\nif _ == false then\n  raise 'Equation #{@base.to_s} failed'\nend"
        else "#{baseTxt}#{@op.text}"
        end
      end
    else
      nil
    end
  end

  # @see Calcula::Expr#children
  # @param (see Calcula::Expr#children)
  # @return (see Calcula::Expr#children)
  def children
    [@base]
  end

  # Creates a prefixed unary expression. Shorthand for
  # `UnaryExpr.new(op, base, prefixed: true)`.
  #
  # @see Calcula::Exprs::UnaryExpr#initialize
  # @see Calcula::Exprs::UnaryExpr#mkPostfix
  # @param op [Calcula::Token] Should have type prefixed with `OP_`
  # @param base [Calcula::Expr]
  # @return [Calcula::Exprs::UnaryExpr] The newly created prefix unary expression
  def self.mkPrefix(op, base)
    new(op, base, prefixed: true)
  end


  # Creates a postfix unary expression. Shorthand for
  # `UnaryExpr.new(op, base, prefixed: false)`.
  #
  # @see Calcula::Exprs::UnaryExpr#initialize
  # @see Calcula::Exprs::UnaryExpr#mkPrefix
  # @param op [Calcula::Token] Should have type prefixed with `OP_`
  # @param base [Calcula::Expr]
  # @return [Calcula::Exprs::UnaryExpr] The newly created postfix unary expression
  def self.mkPostfix(op, base)
    new(op, base, prefixed: false)
  end
end
